package com.cykj.chat.service.impl;



import cn.dev33.satoken.stp.StpUtil;
import com.cykj.chat.mapper.ChatMapper;
import com.cykj.chat.service.EnterpriseModuleFeign;
import com.cykj.chat.service.IChatService;
import com.cykj.common.dto.ResponseDTO;
import com.cykj.common.entity.ChatRecordDO;
import com.cykj.common.entity.ContactInfoDO;
import com.cykj.common.entity.HrDO;
import com.cykj.common.entity.UserDO;
import com.cykj.webSocket.AddWebSocketHandler;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.catalina.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @BelongsProject: smart_recruit_backend
 * @BelongsPackage: com.cykj.chat.service.impl
 * @Author: 蔡张君逸
 * @CreateTime: 2025-08-23 12:19
 * @Description: TODO
 * @Version: 1.0
 */
@Service
public class ChatServiceImpl implements IChatService {
    static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    @Autowired
    private ChatMapper chatMapper;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private EnterpriseModuleFeign enterpriseModuleFeign;

    @Override
    public ResponseDTO getAllMsgs(String myRole, Integer myId, String role) {
        String contactsRedisKey=getContractsRedisKey(myRole,myId,role);
        List<ContactInfoDO> resList = objectMapper.convertValue(redisTemplate.opsForValue().get(contactsRedisKey),
                        new TypeReference<>() {});
//        先看redis
        if(resList!=null){
            resList.sort(new Comparator<ContactInfoDO>() {
                @Override
                public int compare(ContactInfoDO o1, ContactInfoDO o2) {
                    String a= o1.getDraftInfo().isEmpty()?o1.getChatTime():o1.getDraftTime();
                    String b= o2.getDraftInfo().isEmpty()?o2.getChatTime():o2.getDraftTime();
                    return LocalDateTime.parse(b,formatter).compareTo(LocalDateTime.parse(a,formatter));
                }
            });
            if (role.equals("user")){
                for (ContactInfoDO contactInfoDO : resList) {
                    UserDO userInfo = getUserInfo(contactInfoDO.getYourId());
                    if (userInfo != null) {
                        contactInfoDO.setYourName(userInfo.getUsername());
                        contactInfoDO.setYourHeadIcon(userInfo.getHeadIcon());
                    }
                }
            }
            if (role.equals("hr")){
                for (ContactInfoDO contactInfoDO : resList) {
                    HrDO hrInfo = getHrInfo(contactInfoDO.getYourId());
                    if (hrInfo != null) {
                        contactInfoDO.setYourName(hrInfo.getHrName());
                        contactInfoDO.setYourHeadIcon(hrInfo.getHeadIcon());
                    }
                }
            }
            return ResponseDTO.success(resList);
        }
        //redis不存在重新读取并存redis
        List<ContactInfoDO> contactInfoDOList= chatMapper.getContactList(myRole,myId,role);
        LinkedHashMap<String,ContactInfoDO> map=new LinkedHashMap<>(16, 0.75f, true);
//        这里是制造一个专门用来放对方id，自己的未读信息数量，和双方最后一条信息的类
//        利用map同key覆盖的特性，保证最后一条信息。map的key就是对方的id，id和自己的重复无所谓，能覆盖就行和刷新顺序就行
        for (ContactInfoDO contactInfoDO : contactInfoDOList) {
            if (contactInfoDO.getSendRole().equals(myRole)) {
//              发送者是使用者的情况，"对方"就是接收者
                contactInfoDO.setYourRole(contactInfoDO.getReceiveRole());
                contactInfoDO.setYourId(contactInfoDO.getReceiveId());
//                以"发送者" 查看者的id为key
                map.put(String.valueOf(contactInfoDO.getReceiveId()),contactInfoDO);
            }else {
                //接收者是使用者的情况，“对方”就是发送者
                contactInfoDO.setYourRole(contactInfoDO.getSendRole());
                contactInfoDO.setYourId(contactInfoDO.getSendId());
                //以"接收者" 查看者的id为key
                map.put(String.valueOf(contactInfoDO.getSendId()),contactInfoDO);
            }
        }
        resList=new ArrayList<>(map.values());
        for (ContactInfoDO contactInfoDO : resList) {
            int unReadNum= chatMapper.getUnReadNum(contactInfoDO,myRole,myId);
            contactInfoDO.setUnreadNum(unReadNum);
        }

        redisTemplate.opsForValue().set(contactsRedisKey,resList);

        resList.sort(new Comparator<ContactInfoDO>() {
            @Override
            public int compare(ContactInfoDO o1, ContactInfoDO o2) {
                String a= o1.getDraftInfo().isEmpty()?o1.getChatTime():o1.getDraftTime();
                String b= o2.getDraftInfo().isEmpty()?o2.getChatTime():o2.getDraftTime();
                return LocalDateTime.parse(b,formatter).compareTo(LocalDateTime.parse(a,formatter));
            }
        });
        if (role.equals("user")){
            for (ContactInfoDO contactInfoDO : resList) {
                UserDO userInfo = getUserInfo(contactInfoDO.getYourId());
                if (userInfo != null) {
                    contactInfoDO.setYourName(userInfo.getUsername());
                    contactInfoDO.setYourHeadIcon(userInfo.getHeadIcon());
                }
            }
        }
        if (role.equals("hr")){
            for (ContactInfoDO contactInfoDO : resList) {
                HrDO hrInfo = getHrInfo(contactInfoDO.getYourId());
                if (hrInfo != null) {
                    contactInfoDO.setYourName(hrInfo.getHrName());
                    contactInfoDO.setYourHeadIcon(hrInfo.getHeadIcon());
                }
            }
        }

        return ResponseDTO.success(resList);
    }

    @Override
    public ResponseDTO getConcretChat(String myRole, Integer myId, String yourRole, Integer yourRoleId) {
        String contactsRedisKey=getContractsRedisKey(myRole,myId,yourRole);
//        修改自己的联系人列表 全部已读
        List<ContactInfoDO> myList = objectMapper.convertValue
                (redisTemplate.opsForValue().get(contactsRedisKey),
                        new TypeReference<>() {});
        if(myList!=null){
            for (ContactInfoDO contactInfoDO : myList) {
                if (Objects.equals(contactInfoDO.getYourId(), yourRoleId)) {
                    if (contactInfoDO.getUnreadNum()>0){
//                        修改redis已读
                        contactInfoDO.setUnreadNum(0);
                        //        修改数据库已读
                        int res=chatMapper.read(myRole,myId);

                        AddWebSocketHandler.sendMessage(myRole,myId);
                    }
                }
            }
//            存回去
            redisTemplate.opsForValue().set(contactsRedisKey,myList);
        }

//        获取redis聊天记录
        String redisKey=getRecordsRedisKey(myRole,myId,yourRole,yourRoleId);
        List<ChatRecordDO> resList = objectMapper.convertValue( redisTemplate.opsForValue().get(redisKey),new TypeReference<>() {});
        if (resList != null) {
//            修改拿到的聊天记录已读
            for (ChatRecordDO chatRecordDO : resList) {
                chatRecordDO.setIsRead(1);
            }
            return ResponseDTO.success(resList);
        }
//        redis无聊天记录，交互数据库并存储
        List<ChatRecordDO> chatRecordDOS= chatMapper.getConcretChat(myRole,myId,yourRole,yourRoleId);
        if (chatRecordDOS != null) {
            redisTemplate.opsForValue().set(redisKey,chatRecordDOS);
        }
        return ResponseDTO.success(chatRecordDOS);
    }

    @Override
    public ResponseDTO writeRecord(ChatRecordDO chatRecordDO) {
//        System.out.println(chatRecordDO.toString());
//        检测一下发送方是否被对方拉黑
        if(chatRecordDO.getSendRole().equals("user")&&chatRecordDO.getReceiveRole().equals("hr")){
            UserDO userDO=objectMapper.convertValue(redisTemplate.opsForValue().get("hrId:" + chatRecordDO.getReceiveId() + "userInfo:" + chatRecordDO.getSendId()), new TypeReference<UserDO>() {});
            if(userDO!=null){
                if (userDO.getIsBlocked()==1){
                    return ResponseDTO.error("您被hr拉黑了，无法给他发送消息");
                }
            }else {
                userDO=chatMapper.getUserBlockedInfo( chatRecordDO.getSendId(),chatRecordDO.getReceiveId());
                redisTemplate.opsForValue().set("hrId:" + chatRecordDO.getReceiveId() + "userInfo:" + chatRecordDO.getSendId(),userDO);
                if (userDO.getIsBlocked()==1){
                    return ResponseDTO.error("您被hr拉黑了，无法给他发送消息");
                }
            }
        }
        if(chatRecordDO.getSendRole().equals("hr")&&chatRecordDO.getReceiveRole().equals("user")){
            Integer res=chatMapper.getHrIsBlocked(chatRecordDO.getReceiveId(),chatRecordDO.getSendId());
//            理论上等于1就可以了，防止重复拉黑这里设个>0
            if(res!=null){
            if (res>0){
                return ResponseDTO.error("您被user拉黑了，无法给他发送消息");
            }
            }
        }


//        设置一下产生时间
        chatRecordDO.setChatTime(Timestamp.valueOf(LocalDateTime.now()));

        //双方联系人列表若存在则修改双方联系人列表(最后一条消息)。
        // 由于ai可以不需要联系人列表，而非ai要发送消息都需要联系人列表，所以己方联系人列表可以不去判断存在
//        修改自己的联系人列表
        String myContactsRedisKey=getContractsRedisKey(chatRecordDO.getSendRole(),chatRecordDO.getSendId(),chatRecordDO.getReceiveRole());
        List<ContactInfoDO> myList = objectMapper.convertValue
                (redisTemplate.opsForValue().get(myContactsRedisKey),
                        new TypeReference<>() {});
        if(myList!=null){
//            用对方的id查找对象
//            ContactInfoDO removeDO=null;
            for (ContactInfoDO contactInfoDO : myList) {
                if (contactInfoDO.getYourId().equals(chatRecordDO.getReceiveId())) {
                    contactInfoDO.setChatInfo(chatRecordDO.getChatInfo());
                    contactInfoDO.setChatType(chatRecordDO.getChatType());
                    contactInfoDO.setChatTime(LocalDateTime.now().format(formatter));
                    contactInfoDO.setUnreadNum(0);
//                    removeDO=contactInfoDO;
                }
            }
//            myList.remove(removeDO);
//            myList.add(0,removeDO);
//            存回去
            redisTemplate.opsForValue().set(myContactsRedisKey,myList);
        }
//        修改对方的联系人列表，虽然ai不需要，但为了避免其他角色的bug，必须存在
        String yourContactsRedisKey=getContractsRedisKey(chatRecordDO.getReceiveRole(),chatRecordDO.getReceiveId(),chatRecordDO.getSendRole());
        List<ContactInfoDO> yourList = objectMapper.convertValue
                (redisTemplate.opsForValue().get(yourContactsRedisKey),
                        new TypeReference<>() {});
//        如果不存在，让它拉取数据库产生一次redis，避免因为数据库同步原因，导致从数据库拉的和实际不一致
        if (yourList==null){
            getAllMsgs(chatRecordDO.getReceiveRole(),chatRecordDO.getReceiveId(),chatRecordDO.getSendRole());
            yourList=objectMapper.convertValue
                    (redisTemplate.opsForValue().get(yourContactsRedisKey),
                            new TypeReference<>() {});
        }
        if(yourList!=null){
//            用我的id查找对象
            ContactInfoDO removeDO=null;
            for (ContactInfoDO contactInfoDO : yourList) {
                if (contactInfoDO.getYourId().equals(chatRecordDO.getSendId())) {
                    contactInfoDO.setChatInfo(chatRecordDO.getChatInfo());
                    contactInfoDO.setChatType(chatRecordDO.getChatType());
                    contactInfoDO.setUnreadNum(contactInfoDO.getUnreadNum()+1);
                    contactInfoDO.setChatTime(LocalDateTime.now().format(formatter));
                    removeDO=contactInfoDO;
                }
            }
//            如果没有这个removedo，说明对方联系人列表不存在发送者，就是新人发送的消息，所以新增对方的联系人列表
            if(removeDO==null){
//                这是对方的联系人列表，所以对方的yourId就是我的send
                ContactInfoDO contactInfoDO = new ContactInfoDO();
                contactInfoDO.setYourId(chatRecordDO.getSendId());
                contactInfoDO.setYourRole(chatRecordDO.getSendRole());
                contactInfoDO.setChatInfo(chatRecordDO.getChatInfo());
                contactInfoDO.setChatType(chatRecordDO.getChatType());
                contactInfoDO.setUnreadNum(1);
                contactInfoDO.setChatTime(LocalDateTime.now().format(formatter));
                yourList.add(contactInfoDO);
            }
//            这个是之前没有进行时间排序，手动排序的留存
//            else {
//                yourList.remove(removeDO);
//                yourList.add(0, removeDO);
//            }
//            存回去
            redisTemplate.opsForValue().set(yourContactsRedisKey,yourList);
        }

//        增加redis的聊天记录
        String redisKey=getRecordsRedisKey(chatRecordDO.getSendRole(),chatRecordDO.getSendId(),chatRecordDO.getReceiveRole(),chatRecordDO.getReceiveId());
        List<ChatRecordDO> chatList = objectMapper.convertValue(redisTemplate.opsForValue().get(redisKey), new TypeReference<>() {});
//        一般来讲不需要，因为既然发消息了，说明其中一方已经把聊天记录的redis拉出来了。这里以防万一，写一个
        if (chatList==null) {
            getConcretChat(chatRecordDO.getSendRole(),chatRecordDO.getSendId(),chatRecordDO.getReceiveRole(),chatRecordDO.getReceiveId());
        }
        if (chatList != null) {
            chatList.add(chatRecordDO);
            redisTemplate.opsForValue().set(redisKey,chatList);
        }
//       sql语句增加数据库 目前被schedule定时统一添加替代
//        int res=chatMapper.addRecord(chatRecordDO);

//        向双方的socket发送消息，他们若在线则接收消息重新渲染一遍前端
        AddWebSocketHandler.sendMessage(chatRecordDO.getSendRole(),chatRecordDO.getSendId());
        AddWebSocketHandler.sendMessage(chatRecordDO.getReceiveRole(),chatRecordDO.getReceiveId());
        return ResponseDTO.success();
    }

    @Override
    public ResponseDTO talkToNewOne(String myRole, Integer myId, String yourRole, Integer yourRoleId) {
//        在自己的联系人列表设置一个新的联系对象
        String contactsRedisKey=getContractsRedisKey(myRole,myId,yourRole);
        ContactInfoDO contactInfoDO = new ContactInfoDO();
        contactInfoDO.setYourId(yourRoleId);
        contactInfoDO.setYourRole(yourRole);
        contactInfoDO.setChatTime(LocalDateTime.now().format(formatter));

        List<ContactInfoDO> myList = objectMapper.convertValue
                (redisTemplate.opsForValue().get(contactsRedisKey),
                        new TypeReference<>() {});
        if (myList == null) {
            //没有联系人列表，redis没生成
            //先生成一下，就算没有和任何人的聊天信息，也应该生成一个空列表进去
            getAllMsgs(myRole,myId,yourRole);
            myList = objectMapper.convertValue
                    (redisTemplate.opsForValue().get(contactsRedisKey),
                            new TypeReference<>() {});
        }
        for (ContactInfoDO infoDO : myList) {
            if (Objects.equals(infoDO.getYourId(), contactInfoDO.getYourId())){
                return ResponseDTO.error("重复新建联系人");
            }
        }
//        增加这个联系对象
        myList.add(contactInfoDO);
//        存回redis
        redisTemplate.opsForValue().set(contactsRedisKey,myList);
//      给自己发送消息，让前端重新渲染
        AddWebSocketHandler.sendMessage(myRole,myId);

        return ResponseDTO.success();
    }

    @Override
    public ResponseDTO getCommonExpression(String role) {
        if (redisTemplate.opsForValue().get("commmonExpressions:"+role)!=null) {
            List<String> commonExpressionList= (List<String>) redisTemplate.opsForValue().get("commmonExpressions:"+role);
            return ResponseDTO.success(commonExpressionList);
        }
        List<String> commonExpressionList=chatMapper.getCommonExpression(role);
        redisTemplate.opsForValue().set("commmonExpressions:"+role,commonExpressionList);
        return ResponseDTO.success(commonExpressionList);
    }

    @Override
    public ResponseDTO updateDraft(String myRole, Integer myId, String yourRole, Integer yourRoleId, String draft) {
        String contactsRedisKey=getContractsRedisKey(myRole,myId,yourRole);
        List<ContactInfoDO> resList = objectMapper.convertValue(redisTemplate.opsForValue().get(contactsRedisKey),
                new TypeReference<>() {});
        if (resList == null) {
            return ResponseDTO.success();
        }

        for (ContactInfoDO contactInfoDO : resList) {
            if (contactInfoDO.getYourId().equals(yourRoleId)) {
                contactInfoDO.setDraftInfo(draft);
                contactInfoDO.setDraftTime(LocalDateTime.now().format(formatter));
            }
        }
        redisTemplate.opsForValue().set(contactsRedisKey,resList);
        AddWebSocketHandler.sendMessage(myRole,myId);
        return ResponseDTO.success();
    }

    @Override
    public ResponseDTO getDraft(String myRole, Integer myId, String yourRole, Integer yourRoleId) {
        String contactsRedisKey=getContractsRedisKey(myRole,myId,yourRole);
        List<ContactInfoDO> resList = objectMapper.convertValue(redisTemplate.opsForValue().get(contactsRedisKey),
                new TypeReference<>() {});
        if (resList!=null) {
            for (ContactInfoDO contactInfoDO : resList) {
                if (contactInfoDO.getYourId().equals(yourRoleId)) {
                    return ResponseDTO.success(contactInfoDO.getDraftInfo());
                }
            }
        }
        return ResponseDTO.success();
    }


    //    获取联系人列表的rediskey名称
    public String getContractsRedisKey(String myRole,Integer myId,String role) {
        return "contactList:"+myRole+"&"+role + ":Id" + myId;
    }
//    获取聊天信息的rediskey名称
    public String getRecordsRedisKey(String myRole, Integer myId, String yourRole, Integer yourRoleId) {
//        这里的比较是保证双方redis聊天记录存的key一致
        if (myRole.compareTo(yourRole)>=0) {
            return "records:" + myRole + "&" + yourRole + ":" + myId + "&" + yourRoleId;
        }else
        {
            return "records:" + yourRole + "&" + myRole + ":" + yourRoleId + "&" + myId;
        }
    }
//获取用户信息
    public UserDO getUserInfo(int userId) {
        if (redisTemplate.opsForValue().get("userSimplInfo:" + userId) != null) {
            return objectMapper.convertValue(redisTemplate.opsForValue().get("userSimplInfo:" + userId),new TypeReference<UserDO>(){});
        }
        UserDO userDO = chatMapper.getUserInfo(userId);
        redisTemplate.opsForValue().set("userSimplInfo:" + userId,userDO,30, TimeUnit.MINUTES);
        return objectMapper.convertValue(redisTemplate.opsForValue().get("userSimplInfo:" + userId),new TypeReference<UserDO>(){});
    }
    //获取hr信息
    public HrDO getHrInfo(int hrId) {
        if (redisTemplate.opsForValue().get("hrSimplInfo:"+hrId) != null) {
            return objectMapper.convertValue(redisTemplate.opsForValue().get("hrSimplInfo:" + hrId),new TypeReference<HrDO>(){});
        }
        HrDO hrDO = chatMapper.getHrInfo(hrId);
        redisTemplate.opsForValue().set("hrSimplInfo:"+hrId,hrDO,30, TimeUnit.MINUTES);
        return objectMapper.convertValue(redisTemplate.opsForValue().get("hrSimplInfo:" + hrId),new TypeReference<HrDO>(){});
    }

}